let _Vue = null
export default class VueRouter {
  /**
   * 创建install 静态方法
   * @param {vue 实例} Vue
   */
  static install (Vue) {
    // 1. 判断当前的实例是否已经安装过
    if (VueRouter.install.installled) {
      return
    }
    VueRouter.install.installled = true
    // 2. 把vue构造函数记录到全局变量,将来在 VueRouter的实例中要使用到vue，比如Vue.component()
    _Vue = Vue
    // 3. 把创建vue 实例传入的router对象注入到Vue 实例
    // 为了把 router 共享到所有的组件中，将其挂载到Vue 的原型上
    // 以下写法错误：由于this 指向的是VueRouter , 而不是 Vue实例
    // _Vue.prototype.$router = this.$options.router
    // 使用 混入 来解决
    _Vue.mixin({
      // 所有组件都混入这个beforeCreated
      beforeCreate () {
        // 只有vue实例需要挂载router，组件不挂载
        if (this.$options.router) { // 组件的options 中不会有router 对象
          // 此时 this 指向的是Vue 实例
          _Vue.prototype.$router = this.$options.router
          this.$options.router.init()
        }
      }
    })
  }

  constructor (options) {
    this.mode = options.mode !== undefined ? options.mode : 'hash'
    this.options = options
    // data 是个响应式属性，存储的是当前的路由地址, 当路由发生变化的时候，要加载对应组件，所以要设计成一个响应式对象
    this.data = _Vue.observable({
      // 存储当前的路由
      current: '/'
    })
    // 把options 中的路由规则存储进来， key为路由地址path，value 为 组件名称
    this.routeMap = {}
  }

  // 初始化
  init () {
    this.initRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  // 遍历options 中的所有的路由规则,将path 作为 键，component 作为 值，存放到routeMap这个对象中
  // 方便通过 路由地址，直接能够找到对应要渲染的组件
  initRouteMap () {
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  // 初始化router-link 和 router-view 这两个组件
  initComponents (Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      // 运行时编译器不能编译tempalte 模板，需要编写 render 函数
      // template: '<a :href="to"><slot></slot></a>'
      render (h) {
        return h(
          'a',
          {
            attrs: {
              href: this.to
            },
            on: {
              click: this.clickHandler
            }
          }, [this.$slots.default]
        )
      },
      methods: {
        clickHandler (e) {
          if (this.$router.mode !== 'hash') {
            // 1. 将地址栏中的地址改成即将要跳转的路由地址
            history.pushState({}, '', this.to)
            // 2. 要将地址记录到routMap 的current 中
            this.$router.data.current = this.to
          } else if (this.$router.mode === 'hash') {
            window.location.hash = this.to
          }
          // window.location.hash = this.to
          // this.$router.data.current = this.to
          e.preventDefault()
        }
      }
    })
    const self = this
    Vue.component('router-view', {
      render (h) {
        // 根据当前的路由地址在routeMap 中找到对应的组件
        const component = self.routeMap[self.data.current]
        // 将组件通过h函数交给虚拟Dom

        return h(component)
      }
    })
  }

  initEvent () {
    // 注册popstate事件
    window.addEventListener('popstate', () => {
      // data 是个响应式对象，当点击浏览器中的前进或后退，只需从地址栏中取出路由地址，
      // 改变 data.current 即可完成组件的切换
      this.data.current = location.pathname
    })
    // 注册hashchange 事件
    window.addEventListener('hashchange', (e) => {
      const newUrl = e.newURL
      this.data.current = newUrl.substr(newUrl.indexOf('#') + 1)
    })
  }
}
